package com.anywhere.freightman.system.service.impl;

import com.anywhere.freightman.common.BaseEntityService;
import com.anywhere.freightman.common.BaseMapper;
import com.anywhere.freightman.common.entity.user.Account;
import com.anywhere.freightman.common.entity.user.UserQueryEntity;
import com.anywhere.freightman.common.enumeration.CommonStatus;
import com.anywhere.freightman.common.enumeration.YesOrNo;
import com.anywhere.freightman.common.ex.CustomException;
import com.anywhere.freightman.common.ex.ForbiddenException;
import com.anywhere.freightman.common.utils.BPwdEncoderUtils;
import com.anywhere.freightman.order.model.CompanyModel;
import com.anywhere.freightman.order.service.ICompanyService;
import com.anywhere.freightman.system.dao.UserDao;
import com.anywhere.freightman.system.model.AccessToken;
import com.anywhere.freightman.system.model.Resource;
import com.anywhere.freightman.system.model.Role;
import com.anywhere.freightman.system.model.UserModel;
import com.anywhere.freightman.system.service.IAccessTokenService;
import com.anywhere.freightman.system.service.IRoleService;
import com.anywhere.freightman.system.service.IUserService;
import com.google.common.collect.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.weekend.Weekend;
import tk.mybatis.mapper.weekend.WeekendCriteria;

import java.util.Date;
import java.util.List;
import java.util.Set;

@Service
@Transactional
public class UserService extends BaseEntityService<UserModel, UserQueryEntity> implements IUserService {

    @Autowired
    private UserDao userDao;
    @Autowired
    private IAccessTokenService accessTokenService;
    @Autowired
    private IRoleService roleService;
    @Autowired
    private ICompanyService companyService;

    @Override
    public BaseMapper<UserModel> getBaseDao() {
        return userDao;
    }

    @Override
    public Example getExample(UserQueryEntity entity) {
        Weekend<UserModel> weekend = Weekend.of(UserModel.class);
        WeekendCriteria<UserModel, Object> criteria = weekend.weekendCriteria();

        if (entity == null) {
            return weekend;
        }

        if (entity.getExUserId() != null) {
            criteria.andNotEqualTo("id", entity.getExUserId());
        }

        if (entity.getUserType() != null) {
            criteria.andEqualTo("type", entity.getUserType());
        }

        if (entity.getCompanyId() != null && entity.getCompanyId() > 0) {
            criteria.andEqualTo("companyId", entity.getCompanyId());
        }

        if (!StringUtils.isEmpty(entity.getUsername())) {
            criteria.andLike("username", "%" + entity.getUsername() + "%");
        }

        if (!StringUtils.isEmpty(entity.getNickname())) {
            criteria.andLike("nickname", "%" + entity.getNickname() + "%");
        }

        return weekend;
    }

    @Override
    public void insert(UserModel model) {
        insert(model, CommonStatus.ENABLE);
    }

    @Override
    public UserModel selectByMobilePhone(String mobilePhone) {
        return userDao.selectByMobilePhone(mobilePhone);
    }

    @Override
    public UserModel selectByUsername(String username) {
        return userDao.selectByUsername(username);
    }

    @Override
    public Account selectByToken(String token) {
        AccessToken accessToken = accessTokenService.getByToken(token);
        if (accessToken != null) {
            UserModel userModel = getById(accessToken.getUserId());
            Account account = new Account();
            BeanUtils.copyProperties(userModel, account);
            return account;
        } else {
            return null;
        }
    }

    @Override
    public Account login(String username, String password) {
        UserModel userModel = userDao.selectByUsername(username);

        if (userModel == null || !BPwdEncoderUtils.matches(password, userModel.getPassword())) {
            throw new CustomException("账号或密码错误");
        }

        if (!userModel.getStatus().equals(CommonStatus.ENABLE)) {
            throw new CustomException("账号未启用，请联系管理员");
        }
        Account account = new Account();
        BeanUtils.copyProperties(userModel, account);

        Set<Resource> resources = roleService.getResourceByUserId(userModel.getId());
        account.setResources(resources);

        AccessToken token = accessTokenService.insert(userModel.getId());
        account.setToken(token.getToken());

        CompanyModel company = companyService.getById(account.getCompanyId());
        account.setCompany(company);

        return account;
    }

    @Override
    public void updatePwd(long id, String pwd, String newPwd) {
        UserModel model = getById(id);
        if (model == null) {
            throw new CustomException("账号不存在");
        }
        if (!BPwdEncoderUtils.matches(pwd, model.getPassword())) {
            throw new CustomException("密码错误");
        }
        String password = BPwdEncoderUtils.BCryptPassword(newPwd);
        model.setPassword(password);
        update(model);
    }

    @Override
    public void updatePwd(long id, String newPwd) {
        UserModel model = getById(id);
        if (model == null) {
            throw new CustomException("账号不存在");
        }
        String password = BPwdEncoderUtils.BCryptPassword(newPwd);
        model.setPassword(password);
        update(model);
    }

    @Override
    public void updateRole(long id, List<Long> roleIds) {
        roleService.deleteRole(id);
        Role baseRole = roleService.getByCode("BASE_ROLE");
        if (baseRole != null && !roleIds.contains(baseRole.getId())) {
            roleIds.add(baseRole.getId());
        }
        roleService.insertRole(id, roleIds);
    }

    @Override
    public Set<Resource> getResources(long userId) {
        return roleService.getResourceByUserId(userId);
    }

    @Override
    public Set<Resource> getResources(String token) {
        AccessToken accessToken = accessTokenService.getByToken(token);
        if (accessToken == null) {
            throw new ForbiddenException();
        }
        return getResources(accessToken.getUserId());
    }

    @Override
    public List<UserModel> getListByCompanyId(Long companyId) {
        return userDao.getListByCompanyId(companyId);
    }

    @Override
    public void insert(UserModel model, CommonStatus status) {
        if (selectByMobilePhone(model.getMobilePhone()) != null) {
            throw new CustomException("电话号码已经被使用");
        }

        if (selectByUsername(model.getUsername()) != null) {
            throw new CustomException("用户名已经被使用");
        }

        if (model.getCompanyId() == null) {
            model.setCompanyId(0L);
        }

        model.setPassword(BPwdEncoderUtils.BCryptPassword(model.getPassword()));
        model.setRegDatetime(new Date());
        model.setStatus(status);
        model.setDeleted(YesOrNo.NO);
        model.setId(null);
        super.insert(model);

        Role baseRole = roleService.getByCode("BASE_ROLE");
        if (baseRole != null) {
            updateRole(model.getId(), Lists.newArrayList(baseRole.getId()));
        }
    }
}
